home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 January: Mac OS SDK / Dev.CD Jan 98 SDK2.toast / Development Kits (Disc 2) / QuickDraw GX / Programming Stuff / Sample Code / Printing Samples / Applications… / Banana Jr. ƒ / menus & windows.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-04-27  |  17.1 KB  |  663 lines  |  [TEXT/KAHL]

  1. /*
  2.     menus & windows.c
  3.     
  4.     This file contains the menu and window handling routines.
  5.  
  6.     Created        9/2/92                - Dave Hersey 
  7.  
  8.     ----------------------------------------------
  9.  
  10.     2/93    debugged and plopped on GX CD.  - dmh
  11.     9/93    updated to run with the ß2 "GXified" interface files - PLA
  12.     5/94    Fixed some bad, bad, viewport-confused code.  - dmh
  13.     8/94    Universalized.  - dmh
  14. */
  15.  
  16. #include <stdio.h>
  17. #include <Desk.h>
  18. #include <events.h>
  19. #include <windows.h>
  20.  
  21. #include <FontLibrary.h>
  22. #include <GraphicsLibraries.h>
  23. #include <GXEnvironment.h>
  24. #include <GXErrors.h>
  25. #include <QDLibrary.h>
  26. #include <GXPrinting.h>
  27.  
  28. #include "Banana Jr.h"
  29.  
  30. #define    kOSEvent                    app4Evt    /* event used by MultiFinder                    */
  31. #define    kSuspendResumeMessage        1        /* high byte of suspend/resume event message    */
  32. #define    kResumeMask                    1        /* bit of message field for resume vs. suspend    */
  33.  
  34.  
  35. /*------ DoDocInit ------------------------------------------------------------*/
  36. //
  37. //    In this function we create and gxInitialize the the private document structure
  38. //    for a new window.  This structure contains the print job and one page gxShape
  39. //    initially.  New pages may be added later.  We store a handle to this data in
  40. //    the window's refCon field for easy retrieval.  By doing this rather than using
  41. //    globals, we can create many windows containing unique print jobs, formats and
  42. //    pages. 
  43. //
  44. OSErr DoDocInit(wind)
  45. WindowPtr wind;
  46. {
  47.     OSErr    err;
  48.     gxJob    docJob = nil;
  49.     TH_Doc    windDoc = nil;
  50.     short    newPage;
  51.  
  52. //    Create a print job for this document.  This will be the same as the system
  53. //    default until the user goes through the dialogs for Page Setup or Print…
  54.  
  55.     err = GXNewJob(&docJob);
  56.     
  57.     
  58. //    If there are no errors, install our overrides for the format dialog (which
  59. //    will add our panel to it) and gxPrintingEvent (which will allow us to update
  60. //    our windows as the printing dialogs are moved around.  Create a handle the
  61. //    size of our document structure and store the print job and one page description
  62. //    in it.  Store the handle in the window's refCon field so that we can get at it.
  63. //    (Note that the utility routines "GetDocJob" and "GetDocShape" can be used to do
  64. //    this easily.)
  65.  
  66.  
  67.     if (!err)
  68.     {
  69.         GXInstallApplicationOverride(docJob, gxFormatDialogMsg,  NewGXFormatDialogProc(PageFormatDialog));
  70.         GXInstallApplicationOverride(docJob, gxPrintingEventMsg, NewGXPrintingEventProc(MyPrintingEventOverride));
  71.  
  72.         windDoc = (TH_Doc) NewHandleClear(sizeof(T_Doc));
  73.  
  74.         if (!windDoc)
  75.             err = MemError();
  76.         else
  77.         {
  78.             (*windDoc)->docJob = docJob;
  79.             (*windDoc)->numPages = 0;
  80.             (*windDoc)->curPage = 1;
  81.  
  82.             newPage = 1;
  83.  
  84.             (*windDoc)->window = wind;
  85.             (*windDoc)->viewPort = GXNewWindowViewPort(wind);            
  86.             err = AddPage(windDoc, &newPage);
  87.  
  88.             if (!err)
  89.                 SetWRefCon(wind, (long) windDoc);
  90.         }
  91.     }
  92.     
  93.     if (err)
  94.     {
  95.           if (windDoc) DisposeHandle((Handle)windDoc);
  96.         if (docJob) GXDisposeJob(docJob);
  97.     }
  98.     
  99.     return err;
  100. }
  101.  
  102.  
  103. /*------ DoDraw ---------------------------------------------------------------------------------------*/
  104. //
  105. //    Draw the contents of the window.
  106. // 
  107. void DoDraw(wind)
  108. WindowPtr wind;
  109. {
  110.      TH_Doc    doc;
  111.      gxShape    pageShape;
  112.      short    curPage;
  113.      
  114.      doc = GetDoc(wind);
  115.      curPage = (*doc)->curPage;
  116.  
  117.      GXDrawShape(GetDocShape(doc, curPage));
  118. }
  119.  
  120.  
  121. /*------ CreateSampleImage ----------------------------------------------------------------------------*/
  122. //
  123. //    This function adds a simple shape to the page indicated
  124. //    in the passed document.
  125. //
  126. void CreateSampleImage(TH_Doc doc, short whichPg)
  127. {
  128.     TH_Page            docPage;
  129.     gxShape         pageShape, theText;
  130.     gxColor         textColor;
  131.     Str255            textStr;
  132.     unsigned char    numChars, loop;
  133.     short            numPages;
  134.         
  135.     numPages = (*doc)->numPages;
  136.  
  137. // Retrieve the page gxShape so we can add to it.
  138.  
  139.     docPage = GetDocPage(doc, whichPg);
  140.     pageShape = (*docPage)->pageShape;
  141.  
  142.     numChars = sprintf((Ptr) &textStr[0], "%s %i %s", "This was added when there were", numPages -1, "pages");
  143.     theText = GXNewText(numChars, (unsigned char *) textStr,  nil);
  144.     SetShapeCommonFont(theText, timesFont);
  145.     GXSetShapeTextSize(theText, ff(30));
  146.     GXMoveShapeTo (theText, ff(10), ff(30));
  147.  
  148. // Create an hsv gxColor space
  149.  
  150.     textColor.space = gxHSVSpace;
  151.     textColor.profile = nil;
  152.     textColor.element.hsv.hue = 0x7400;
  153.     textColor.element.hsv.saturation = 0xFFFF;
  154.     textColor.element.hsv.value = 0xFFFF;
  155.  
  156.     for (loop = 1; loop < 14; loop++)
  157.     {
  158.         GXSetShapeColor(theText, &textColor);
  159.         AddToShape(pageShape, theText);
  160.         if (loop < 7)
  161.             GXMoveShape(theText, ff(10), ff(35));
  162.         else
  163.             GXMoveShape(theText, ff(-10), ff(35));
  164.         textColor.element.hsv.hue += 0x0800;
  165.     }
  166.  
  167.     GXDisposeShape(theText); 
  168. }
  169.  
  170.  
  171. /*------ DoCreateNew ---------------------------------------------------------------------------------*/
  172. //
  173. //    This routine is called when a window needs to be created.
  174. //
  175. OSErr DoCreateNew(void)
  176. {
  177.     OSErr        err;
  178.     WindowPtr    wind;
  179.     
  180.     /** Create a window, attach a default viewPort to it, create and initialize our private data for it, and
  181.     /** add a sample image to its page shape. **/
  182.  
  183.     wind = NewWindow(nil, &gWindowQDRect, gWindowTitle, true, noGrowDocProc, (WindowPtr)-1L, true, 0L);
  184.     
  185.     if (!wind)
  186.         err = MemError();
  187.     else
  188.         err = DoDocInit(wind);
  189.     
  190. // Invalidate the window's portRect so that everything gets updated.
  191.  
  192.     SetPort(wind);
  193.     InvalRect(&wind->portRect);
  194.     return err;
  195. }
  196.  
  197.  
  198. /*------ DoDispose -------------------------------------------------------------------------------------*/
  199. //
  200. //    This routine is called when a window needs to be disposed of.
  201. //
  202. void DoDispose(WindowPtr wind)
  203. {
  204.     TH_Doc    doc;
  205.     short    numPages, pg;
  206.     
  207.     /**  
  208.         You should always dispose of your GX graphics objects before tossing your window. Why? It's generally good 
  209.         form and this approach guarantees that everything is disposed. If you had not disposed of everything, the
  210.         call to DisposeWindow should dispose of the objects. If you are running the debugging version of the 
  211.         SecretGraphics init with notices set, you will receive a notice that you had not disposed of everything. You
  212.         can turn notices on in this file by setting gDebugging = TRUE (above).
  213.     **/
  214.     
  215.     doc = GetDoc(wind);                        // Get the handle to our document structure.
  216.     numPages = (*doc)->numPages;            // Get the number of pages in our document.
  217.  
  218.     for (pg = numPages; pg >= 1; pg--)
  219.         DisposePage(doc, pg);                 // Dispose of each page's info and shapes.
  220.  
  221.     GXDisposeJob(GetDocJob(doc));            // Dispose of this doc's print job.
  222.     DisposHandle((Handle) doc);                // Dispose of our private data.
  223.        DisposeWindow(wind);                    // Dispose of the window.
  224. }
  225.  
  226.  
  227.  
  228. /*------ AddPage -------------------------------------------------------------------------------------*/
  229. //
  230. //    This routine is called when a page needs to be added to a document.  The
  231. //    page is added AFTER the page number passed.  If whichPg is greater than
  232. //    the last page, the new page is added to the end of the document.  If
  233. //    whichPg is less than 1, the page is added to the beginning of the doc.
  234. //    The page number of the new page is returned in whichPg.
  235. //
  236. OSErr AddPage(TH_Doc doc, short *whichPg)
  237. {
  238.     OSErr        err;
  239.     gxJob        docJob = nil;
  240.     gxShape        pageShape = nil;
  241.     TH_Page        docPage;
  242.     TH_Page        page;
  243.     short        numPages;
  244.     short        aPage;
  245.     long        newSize;
  246.  
  247.     numPages = (*doc)->numPages;
  248.  
  249. // Pin the page number to insert after to the range (0, numPages).
  250.  
  251.     *whichPg = (*whichPg < 1)? 0: (*whichPg < numPages)? *whichPg: numPages;
  252.  
  253. //    Create the page gxShape. We set the unique items attribute to make sure that each
  254. //    item added to the picture has a unique reference.
  255.  
  256.     pageShape = GXNewShape(gxPictureType);
  257.     GXSetShapeViewPorts(pageShape, 1, &(*doc)->viewPort);            
  258.     GXSetShapeAttributes(pageShape, GXGetShapeAttributes(pageShape) | gxUniqueItemsShape);
  259.     
  260.     docPage = (TH_Page) NewHandleClear(sizeof(T_Page));
  261.  
  262.     if (!docPage)
  263.         err = MemError();
  264.     else
  265.     {
  266.         newSize = GetHandleSize((Handle) doc) + sizeof(T_Page);
  267.         SetHandleSize((Handle) doc, newSize);
  268.         err = MemError();
  269.         
  270.         if (!err)
  271.         {
  272.             (*docPage)->pageFormat = GXNewFormat((*doc)->docJob);
  273.             (*docPage)->pageShape = pageShape;
  274.             numPages = ++(*doc)->numPages;
  275.             ++*whichPg;
  276.  
  277.             if ((*whichPg < numPages) && (numPages > 1))
  278.                 for (aPage = numPages; aPage > *whichPg; aPage--)
  279.                     (*doc)->docPage[aPage -1] = (*doc)->docPage[aPage -2];
  280.  
  281.             (*doc)->docPage[*whichPg -1] = docPage;
  282.             CreateSampleImage(doc, *whichPg);
  283.         }
  284.     }
  285.     
  286.     return err;
  287. }
  288.  
  289.  
  290.  
  291. /*------ DisposePage -------------------------------------------------------------------------------------*/
  292. //
  293. //    This routine is called when a page in a document needs to be disposed of.
  294. //    It's smart enough to allow you to delete a page from the middle of the
  295. //    document, not just from the end.
  296. //
  297. void DisposePage(TH_Doc doc, short    whichPg)
  298. {
  299.     TH_Page        page;
  300.     short        numPages;
  301.     short        pageNum;
  302.     long        newSize;
  303.  
  304.     if (whichPg > (*doc)->numPages) return;    // ?!  There aren't that many pages!!
  305.     if (whichPg < 1) return;                // ?!  Page numbers start at 1!!
  306.     
  307.     page = GetDocPage(doc, whichPg);        // Get the page in question and
  308.     GXDisposeShape((*page)->pageShape);        // delete its gxShape,
  309.     GXDisposeFormat((*page)->pageFormat);        // format,
  310.     DisposeHandle((Handle) page);            // and free up the memory it occupies.
  311.  
  312.     numPages = --(*doc)->numPages;            // We now have one less page in our document.
  313.  
  314.  
  315. // If the page we deleted was not at the end of the document, we need to move
  316. // all following pages down one.  In other words, if page 5 is deleted, page 6
  317. // becomes page 5, page 7 becomes page 6 and so forth.  When done, resize the
  318. // handle to the document's info, since we no longer need the room occupied by
  319. // the deleted page's info.
  320.  
  321.     if (whichPg <= numPages)
  322.     {
  323.         for (pageNum = whichPg; pageNum <= numPages +1; pageNum++)
  324.             (*doc)->docPage[pageNum -1] = (*doc)->docPage[pageNum];
  325.  
  326.         newSize = GetHandleSize((Handle) doc) - sizeof(T_Page);
  327.         SetHandleSize((Handle) doc, newSize);
  328.     } 
  329. }
  330.  
  331.  
  332.  
  333. /*------ EventLoop ------------------------------------------------------------------------------------*/
  334.  
  335. void EventLoop()
  336. {
  337.     EventRecord        theEvent;
  338.  
  339.     if (WaitNextEvent(everyEvent, &theEvent, gSleep, nil))
  340.         MyDoEvent(&theEvent);
  341. }
  342.  
  343.  
  344. /*------ DoEvent ------------------------------------------------------------------------------------*/
  345.  
  346. void MyDoEvent(EventRecord *theEvent)
  347. {
  348.     char            key;
  349.     WindowPtr         whichWindow;
  350.     GrafPtr            oldPort;
  351.  
  352.     switch(theEvent->what)
  353.     {                    
  354.         case updateEvt:
  355.             if (((WindowPeek) theEvent->message)->windowKind == userKind)
  356.             {
  357.                 GetPort(&oldPort);
  358.                 SetPort((WindowPtr) theEvent->message);
  359.                 BeginUpdate((WindowPtr) theEvent->message);
  360.                 DoDraw((WindowPtr) theEvent->message);
  361.                 EndUpdate((WindowPtr) theEvent->message);
  362.                 SetPort(oldPort);
  363.               }
  364.         break;
  365.         
  366.         case mouseDown:
  367.             switch (FindWindow(theEvent->where, &whichWindow)) {
  368.                 case inSysWindow:
  369.                     SystemClick(theEvent, whichWindow);
  370.                 break;
  371.                         
  372.                 case inDrag:
  373.                     if (((WindowPeek) whichWindow)->windowKind == userKind)
  374.                         DragWindow(whichWindow, theEvent->where, &qd.screenBits.bounds);
  375.                 break;
  376.  
  377.                 case inGoAway:
  378.                     if ((((WindowPeek) whichWindow)->windowKind == userKind) &&
  379.                         (TrackGoAway(whichWindow, theEvent->where)))
  380.                         DoDispose(whichWindow);
  381.                 break;
  382.                 
  383.                 case inContent:
  384.                     if (((WindowPeek) whichWindow)->windowKind == userKind)
  385.                              SelectWindow(whichWindow);
  386.                 break;
  387.                 case inMenuBar:
  388.                     DoMenuCommand(MenuSelect(theEvent->where));
  389.                 break;
  390.  
  391.             }
  392.  
  393.         case keyDown:
  394.         case autoKey:
  395.             key = theEvent->message & charCodeMask;
  396.             if (theEvent->modifiers & cmdKey)
  397.                 if (theEvent->what == keyDown)
  398.                     DoMenuCommand(MenuKey(key));
  399.             break;
  400.  
  401.         case kOSEvent:
  402.             switch ((unsigned long) theEvent->message >> 24) {    /**  high byte of message  **/
  403.                  case kSuspendResumeMessage:            /**  suspend/resume is also an activate/deactivate  **/
  404.                     if ((theEvent->message & kResumeMask) == 0)
  405.                        gSleep = 80;                    /** we are headed to the background, so slow down...  **/
  406.                     else
  407.                     {
  408.                        gSleep = 0;                    /** we are headed to the foreground, so speed up...  **/
  409.  
  410. // On a resume event, we need to call GXUpdateJob on all of our documents'
  411. // jobs.  This is important because the user may have just changed
  412. // something which affects our jobs (like the size of the paper in the
  413. // printer).
  414. //
  415. // Since our application stores our document references in the refCon fields
  416. // of our documents' windows, we just loop through every one of our windows,
  417. // extract our document pointers and update the associated jobs.
  418.  
  419.                         whichWindow = FrontWindow();
  420.                         
  421.                         while (whichWindow != nil)
  422.                         {
  423.                             if (((WindowPeek) whichWindow)->windowKind == userKind)
  424.                                 GXUpdateJob(GetDocJob(GetDoc(whichWindow)));
  425.                             
  426.                             whichWindow = (WindowPtr) ((WindowPeek) whichWindow)->nextWindow;
  427.                         }
  428.                     }
  429.                 break;
  430.             }
  431.        break;
  432.     }
  433. }
  434.  
  435.  
  436. /*------ DoMenuCommand ---------------------------------------------------------------------------------------*/
  437. //
  438. //    This routine handles the dispatching of our menu requests.
  439. //
  440. void DoMenuCommand(long menuResult)
  441. {
  442.     short                menuID;
  443.     short                menuItem;
  444.     Str255                daName;
  445.     OSErr                err;
  446.     gxDialogResult        result;
  447.     TH_Doc                doc;
  448.     short                curPage, numPages, newPage;
  449.     WindowPtr            wind;
  450.     
  451.     menuID = menuResult >>16;
  452.     menuItem = menuResult & 0x0000ffff;
  453.     
  454.     switch (menuID)
  455.     {
  456.         case mApple:
  457.             switch (menuItem)
  458.             {
  459.                 case iAbout:        /* display About box */
  460.                     break;
  461.                 
  462.                 default:            /* handle DA selection */
  463.                     GetItem(GetMHandle(mApple), menuItem, daName);
  464.                     OpenDeskAcc(daName);
  465.                     break;
  466.             }
  467.             break;
  468.             
  469.             case mFile:
  470.                 switch (menuItem)
  471.                 {                        
  472.                     case iNew:
  473.                             /* create new window */
  474.                             
  475.                                 err = DoCreateNew();
  476.                         break;
  477.                                                 
  478.                     case iOpen:
  479.                             /* open saved window */
  480.                             
  481.                         break;
  482.                                                 
  483.                     case iClose:
  484.                             /* close front window */
  485.                             
  486.                                 DoDispose(FrontWindow());
  487.                         break;
  488.                                                 
  489.                     case iSave:
  490.                             /* save front window */
  491.  
  492.                         break;
  493.                                                 
  494.                     case iDocSetup:
  495.                             /* perform document setup */
  496.                                 
  497.                                 HiliteMenu(0);
  498.                                 err = DoDocFormat(FrontWindow(), &result);
  499.                         break;
  500.                                                 
  501.                     case iPageSetup:
  502.                             /* perform page setup */
  503.                             
  504.                                 HiliteMenu(0);
  505.                                 err = DoPageFormat(FrontWindow(), &result);
  506.                         break;
  507.                                                 
  508.                     case iPrintOne:
  509.                             /* perform print one copy */
  510.                             
  511.                             err = MyPrintOneCopy(FrontWindow());
  512.                         break;
  513.                         
  514.                     case iPrint:
  515.                             /* perform print */
  516.                             
  517.                                 HiliteMenu(0);
  518.                                 err = DoPrinting(FrontWindow());
  519.                         break;
  520.  
  521.                     case iQuit:
  522.                         gQuitting = true;
  523.                         break;
  524.                 }
  525.                 break;
  526.                 
  527.             case mEdit:
  528.                 break;
  529.                 
  530.             case mDocument:
  531.                 switch (menuItem)
  532.                 {                        
  533.                     case iAddPage:
  534.                             /* Add a page */
  535.                             
  536.                             wind = FrontWindow();
  537.                             SetPort(wind);
  538.                             doc = GetDoc(wind);
  539.                             newPage = (*doc)->curPage;
  540.                             AddPage(doc, &newPage);
  541.                             (*doc)->curPage = newPage;
  542.                             EraseRect(&wind->portRect);
  543.                             InvalRect(&wind->portRect);
  544.                         break;
  545.                                                 
  546.                     case iDeletePage:
  547.                             /* Delete current page */
  548.                             
  549.                             wind = FrontWindow();
  550.                             SetPort(wind);
  551.                             doc = GetDoc(wind);
  552.                             curPage = (*doc)->curPage;
  553.                             numPages = (*doc)->numPages;
  554.  
  555.                             if (numPages > 1)
  556.                             {
  557.                                 DisposePage(doc, curPage);
  558.  
  559.                                 if (curPage == numPages)
  560.                                     curPage = --(*doc)->curPage;
  561.                                 
  562.                                 EraseRect(&wind->portRect);
  563.                                 InvalRect(&wind->portRect);
  564.                             }
  565.                         break;
  566.                                                 
  567.                     case iNextPage:
  568.                             /* Forward one page */
  569.                             
  570.                             wind = FrontWindow();
  571.                             SetPort(wind);
  572.                             doc = GetDoc(wind);
  573.                             curPage = (*doc)->curPage;
  574.                             numPages = (*doc)->numPages;
  575.  
  576.                             if (curPage < numPages)
  577.                             {
  578.                                 ++(*doc)->curPage;
  579.                                 
  580.                                 EraseRect(&wind->portRect);
  581.                                 InvalRect(&wind->portRect);
  582.                             }
  583.                         break;
  584.                                                 
  585.                     case iPrevPage:
  586.                             /* Back one page */
  587.                             
  588.                             wind = FrontWindow();
  589.                             SetPort(wind);
  590.                             doc = GetDoc(wind);
  591.                             curPage = (*doc)->curPage;
  592.  
  593.                             if (curPage > 1)
  594.                             {
  595.                                 --(*doc)->curPage;
  596.                                 
  597.                                 EraseRect(&wind->portRect);
  598.                                 InvalRect(&wind->portRect);
  599.                             }
  600.                         break;
  601.                 }
  602.                 break;
  603.     }
  604.     HiliteMenu(0);
  605. }
  606.  
  607.  
  608. /*------ GetDoc --------------------------------------------------------------------------------------*/
  609. //
  610. //    This utility routine returns the document structure attached to a window.
  611. //
  612. TH_Doc GetDoc(WindowPtr wind)
  613. {
  614.     TH_Doc    doc = nil;
  615.  
  616.     if (wind) doc = (TH_Doc) GetWRefCon(wind);
  617.     
  618.     return doc;
  619. }
  620.  
  621.  
  622. /*------ GetDocPage ----------------------------------------------------------------------------------*/
  623. //
  624. //    This utility routine returns the specified page structure for the passed document.
  625. //
  626. TH_Page GetDocPage(TH_Doc doc, short whichPg)
  627. {
  628.     TH_Page        page;
  629.  
  630.     page = (*doc)->docPage[whichPg -1];
  631.     
  632.     return page;
  633. }
  634.  
  635.  
  636. /*------ GetDocShape ---------------------------------------------------------------------------------*/
  637. //
  638. //    This utility routine returns the page gxShape (contents) attached to a window's document.
  639. //
  640. gxShape GetDocShape(TH_Doc doc, short whichPg)
  641. {
  642.     TH_Page    docPage;
  643.     gxShape    pageShape = nil;
  644.  
  645.     docPage = (*doc)->docPage[whichPg -1];
  646.     pageShape = (*docPage)->pageShape;
  647.     
  648.     return pageShape;
  649. }
  650.  
  651.  
  652. /*------ GetDocJob -----------------------------------------------------------------------------------*/
  653. //
  654. //    This utility routine returns the print job attached to a window's document.
  655. //
  656. gxJob GetDocJob(TH_Doc doc)
  657. {
  658.     gxJob        docJob = nil;
  659.  
  660.     docJob = (*doc)->docJob;
  661.     return docJob;
  662. }
  663.